# ocr_gui.py
import tkinter as tk
from tkinter import messagebox
import threading
import time
import os
import sys
import difflib

import mss
import pytesseract
from PIL import Image

OUTPUT_FILE = "ocr_result.txt"
OCR_INTERVAL = 2.0  # 秒

# 如果你的 tesseract 不在 PATH，可以在这里指定，例如：
pytesseract.pytesseract.tesseract_cmd = r"C:\\Program Files\\Tesseract-OCR\\tesseract.exe"


class OCRApp:
    def __init__(self, root):
        self.root = root
        self.root.title("屏幕区域 OCR 工具")
        self.capture_region = None  # dict: left, top, width, height
        self.last_text = ""
        self.stop_event = threading.Event()
        self.ocr_thread = None
        self.border_window = None  # 用于显示识别区域边框的窗口

        # UI
        self.select_btn = tk.Button(root, text="选择区域", command=self.select_area)
        self.select_btn.grid(row=0, column=0, padx=8, pady=8)

        self.start_btn = tk.Button(root, text="开始 OCR", command=self.start_ocr)
        self.start_btn.grid(row=0, column=1, padx=8, pady=8)

        self.stop_btn = tk.Button(root, text="停止 OCR", command=self.stop_ocr)
        self.stop_btn.grid(row=0, column=2, padx=8, pady=8)

        self.open_btn = tk.Button(root, text="打开结果文件", command=self.open_output)
        self.open_btn.grid(row=0, column=3, padx=8, pady=8)

        self.status_var = tk.StringVar(value="未选择区域")
        self.status_label = tk.Label(root, textvariable=self.status_var, width=50, anchor="w")
        self.status_label.grid(row=1, column=0, columnspan=4, padx=8)

        self.interval_label = tk.Label(root, text="间隔(s):")
        self.interval_label.grid(row=2, column=0, sticky="e")
        self.interval_var = tk.DoubleVar(value=OCR_INTERVAL)
        self.interval_entry = tk.Entry(root, textvariable=self.interval_var, width=6)
        self.interval_entry.grid(row=2, column=1, sticky="w")

    def select_area(self):
        """弹出透明覆盖层，让用户拖拽选择屏幕区域（使用屏幕坐标）"""
        overlay = tk.Toplevel(self.root)
        overlay.attributes("-fullscreen", True)
        overlay.attributes("-alpha", 0.25)
        overlay.config(cursor="cross")
        overlay.lift()
        overlay.grab_set()

        canvas = tk.Canvas(overlay, bg="black")
        canvas.pack(fill=tk.BOTH, expand=True)

        self._rect = None
        self._start_x = None
        self._start_y = None

        def on_mouse_down(event):
            self._start_x = event.x_root
            self._start_y = event.y_root
            if not self._rect:
                # 初次创建矩形
                self._rect = canvas.create_rectangle(
                    self._start_x, self._start_y, self._start_x, self._start_y,
                    outline="red", width=2
                )

        def on_mouse_drag(event):
            if self._rect:
                # 更新矩形坐标
                canvas.coords(self._rect, self._start_x, self._start_y, event.x_root, event.y_root)

        def on_mouse_up(event):
            x1, y1 = self._start_x, self._start_y
            x2, y2 = event.x_root, event.y_root
            left = int(min(x1, x2))
            top = int(min(y1, y2))
            width = int(abs(x2 - x1))
            height = int(abs(y2 - y1))
            
            if width <= 0 or height <= 0:
                messagebox.showwarning("选择无效", "请选择有效的矩形区域。")
                return

            self.capture_region = {"left": left, "top": top, "width": width, "height": height}
            self.status_var.set(f"已选区域: left={left}, top={top}, w={width}, h={height}")
            overlay.destroy()

        canvas.bind("<ButtonPress-1>", on_mouse_down)
        canvas.bind("<B1-Motion>", on_mouse_drag)
        canvas.bind("<ButtonRelease-1>", on_mouse_up)

        self.root.wait_window(overlay)

    def show_border(self):
        """显示识别区域的边框窗口"""
        if not self.capture_region:
            return
            
        region = self.capture_region
        
        # 创建边框窗口
        self.border_window = tk.Toplevel(self.root)
        self.border_window.title("OCR识别区域")
        
        # 设置窗口位置和大小
        self.border_window.geometry(f"{region['width']+4}x{region['height']+4}+{region['left']-2}+{region['top']-2}")
        
        # 设置窗口属性：置顶、无边框、透明背景
        self.border_window.attributes("-topmost", True)
        self.border_window.overrideredirect(True)
        self.border_window.attributes("-alpha", 0.6)
        
        # 创建画布显示边框
        canvas = tk.Canvas(self.border_window, bg="white", highlightthickness=0)
        canvas.pack(fill=tk.BOTH, expand=True)
        
        # 绘制红色边框
        canvas.create_rectangle(
            2, 2, region['width']+2, region['height']+2,
            outline="red", width=2, fill=""
        )
        
        # 在右上角显示状态信息
        canvas.create_text(
            region['width']-5, 15,
            text="", anchor="ne",
            fill="red", font=("Arial", 10, "bold")
        )

    def hide_border(self):
        """隐藏边框窗口"""
        if self.border_window:
            self.border_window.destroy()
            self.border_window = None

    def start_ocr(self):
        if not self.capture_region:
            messagebox.showinfo("提示", "请先点击【选择区域】并框选要识别的区域。")
            return
        if self.ocr_thread and self.ocr_thread.is_alive():
            messagebox.showinfo("提示", "OCR 已在运行中。")
            return

        try:
            interval = float(self.interval_var.get())
            if interval <= 0:
                raise ValueError
        except Exception:
            messagebox.showwarning("参数错误", "请填写合法的 OCR 间隔（秒）。")
            return

        self.stop_event.clear()
        self.ocr_thread = threading.Thread(target=self.ocr_loop, daemon=True)
        self.ocr_thread.start()
        self.status_var.set("OCR 运行中...")
        
        # 显示识别区域边框
        self.show_border()

    def stop_ocr(self):
        self.stop_event.set()
        self.status_var.set("OCR 已停止")
        
        # 隐藏边框
        self.hide_border()

    def open_output(self):
        path = os.path.abspath(OUTPUT_FILE)
        if not os.path.exists(path):
            messagebox.showinfo("文件不存在", f"{path} 不存在。")
            return
        try:
            if sys.platform == "win32":
                os.startfile(path)
            elif sys.platform == "darwin":
                os.system(f'open "{path}"')
            else:
                os.system(f'xdg-open "{path}"')
        except Exception as e:
            messagebox.showerror("打开失败", str(e))

    @staticmethod
    def extract_new_from(old_text, new_text):
        """对比 old -> new，返回新增行（简单行级别 diff）"""
        diff = difflib.ndiff(old_text.splitlines(), new_text.splitlines())
        new_lines = [line[2:] for line in diff if line.startswith("+ ")]
        return "\n".join(new_lines)

    def ocr_loop(self):
        """在后台线程循环执行截图、OCR、对比、追加写文件"""
        interval = float(self.interval_var.get())
        if not os.path.exists(OUTPUT_FILE):
            open(OUTPUT_FILE, "w", encoding="utf-8").close()

        with mss.mss() as sct:
            while not self.stop_event.is_set():
                region = {
                    "left": int(self.capture_region["left"]),
                    "top": int(self.capture_region["top"]),
                    "width": int(self.capture_region["width"]),
                    "height": int(self.capture_region["height"]),
                }
                try:
                    sct_img = sct.grab(region)
                    pil_img = Image.frombytes("RGB", sct_img.size, sct_img.rgb)
                    text = pytesseract.image_to_string(pil_img, lang="chi_sim+eng").strip()
                except Exception as e:
                    self.status_var.set(f"OCR 出错: {e}")
                    time.sleep(interval)
                    continue

                if text:
                    if self.last_text:
                        new_part = self.extract_new_from(self.last_text, text)
                        if new_part.strip():
                            with open(OUTPUT_FILE, "a", encoding="utf-8") as f:
                                f.write(new_part + "\n")
                            self.root.after(0, lambda: self.status_var.set("发现新增文本并已追加到文件"))
                    else:
                        with open(OUTPUT_FILE, "a", encoding="utf-8") as f:
                            f.write(text + "\n")
                        self.root.after(0, lambda: self.status_var.set("已写入初次识别内容"))

                    self.last_text = text

                time.sleep(interval)


def main():
    root = tk.Tk()
    app = OCRApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()